#include "../../src/detail/redis_impl.hh"
#include "../../src/repo/src/include/root/coroutine/coroutine.h"
#include "../../src/util/time_util.hh"
#include "../framework/unittest.hh"

FIXTURE_BEGIN(test_redis)

 CASE(TestAddHost1) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  ASSERT_TRUE(redis.start());
}

 CASE(TestAddHost2) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(!redis.add_host("test", "xxx.xx.xx.xx", 6379, "", ""));
}

 CASE(TestAddHost3) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(!redis.add_host("", "xxx.xx.xx.xx", 6379, "", ""));
}

 CASE(TestAddHost4) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(!redis.add_host("test", "", 6379, "", ""));
}

 CASE(TestAddHost5) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(!redis.add_host("test", "", -1, "", ""));
}

 CASE(TestAddHost6) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(!redis.add_host("test", "127.0.0.1", 6379, "1", "2"));
}

 CASE(TestDoCommand1) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool done = false;
  bool exist = false;
  auto result = redis.do_command("test", "SET k value", 1000,
                                 [&](const kratos::redis::Result &r, std::uint64_t) {
                                   done = true;
                                   exist = (r.get_reply() != nullptr);
                                 }, 0);
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
  ASSERT_TRUE(done);
}

 CASE(TestDoCommand2) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool done = false;
  bool error = false;
  kratos::redis::RedisError code = kratos::redis::RedisError::SUCCESS;
  auto result = redis.do_command("test", "xxxxxxx", 1000,
                                 [&](const kratos::redis::Result &r, std::uint64_t) {
                                   done = r.is_success();
                                   error = !r.get_error().empty();
                                   code = r.get_error_code();
                                 }, 0);
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
  ASSERT_TRUE(!done);
  ASSERT_TRUE(error);
  ASSERT_TRUE(code != kratos::redis::RedisError::SUCCESS);
}

 CASE(TestDoCommand3) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool done = false;
  auto result = redis.do_command("test", "xxxxxxx", 1000,
                                 [&](const kratos::redis::Result &r, std::uint64_t) {
                                   done = r.is_success();
                                   throw std::runtime_error("");
                                 }, 0);
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
  ASSERT_TRUE(!done);
}

 CASE(TestDoCommand4) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool done = false;
  ASSERT_FALSE(
      redis.do_command("", "SET k value", 1000,
                       [&](const kratos::redis::Result &,std::uint64_t) { done = true; }, 0));
  ASSERT_FALSE(done);
}

 CASE(TestDoCommand5) {
    kratos::redis::RedisImpl redis(nullptr);
    ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
    bool done = false;
    ASSERT_FALSE(
        redis.do_command("ssssss", "SET k value", 1000,
            [&](const kratos::redis::Result&, std::uint64_t) { done = true; }, 0));
    ASSERT_FALSE(done);
}

 CASE(TestDoCommand6) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool done = false;
  ASSERT_FALSE(redis.do_command(
      "test", "", 1000, [&](const kratos::redis::Result &, std::uint64_t) { done = true; }, 0));
  ASSERT_FALSE(done);
}

 CASE(TestDoCommand7) {
    kratos::redis::RedisImpl redis(nullptr);
    ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
    bool done = false;
    bool exist = false;
    auto result = redis.do_command("test", "SET k value", 0,
        [&](const kratos::redis::Result& r, std::uint64_t) {
            done = true;
            exist = (r.get_reply() != nullptr);
        }, 0);
    auto start = kratos::util::get_os_time_millionsecond();
    while (true) {
        auto ms = kratos::util::get_os_time_millionsecond();
        if (ms - start > 1000) {
            break;
        }
        redis.update(ms);
    }
    ASSERT_TRUE(result);
    ASSERT_TRUE(done);
}


 CASE(TestDoCommandCo1) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool result = false;
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", "SET k value", 1000);
    result = ret->is_success();
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
}

 CASE(TestDoCommandCo2) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  ASSERT_FALSE(redis.do_command_co("test", "", 1000));
}

 CASE(TestDoCommandCo3) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  ASSERT_FALSE(redis.do_command_co("", "SET k value", 1000));
}

 CASE(TestDoCommandCo4) {
    kratos::redis::RedisImpl redis(nullptr);
    ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
    bool result = false;
    coro_start([&](void*) {
        auto ret = redis.do_command_co("test", "SET k value", 0);
        result = ret->is_success();
        });
    auto start = kratos::util::get_os_time_millionsecond();
    while (true) {
        auto ms = kratos::util::get_os_time_millionsecond();
        if (ms - start > 1000) {
            break;
        }
        redis.update(ms);
    }
    ASSERT_TRUE(result);
}

 CASE(TestDoCommandCo5) {
    kratos::redis::RedisImpl redis(nullptr);
    ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
    bool result = false;
    coro_start([&](void*) {
        auto ret = redis.do_command_co("txxxxest", "SET k value", 0);
        result = !ret;
        });
    auto start = kratos::util::get_os_time_millionsecond();
    while (true) {
        auto ms = kratos::util::get_os_time_millionsecond();
        if (ms - start > 1000) {
            break;
        }
        redis.update(ms);
    }
    ASSERT_TRUE(result);
}

CASE(TestResult1) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool result = false;
  bool retval = false;
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", "SET k value", 1000);
    retval = ret->get_return(result);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
  ASSERT_TRUE(retval);
}

CASE(TestResult2) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  std::string result;
  bool retval = false;
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", "GET k", 1000);
    retval = ret->get_return(result);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result == "value");
  ASSERT_TRUE(retval);
}

CASE(TestResult3) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  std::size_t result = 0;
  bool retval = false;
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", "GET k", 1000);
    retval = ret->get_return(result);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(!result);
  ASSERT_TRUE(!retval);
}

CASE(TestResult4) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  std::size_t result = 0;
  bool retval = false;
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", "EXISTS k", 1000);
    retval = ret->get_return(result);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result == 1);
  ASSERT_TRUE(retval);
}

CASE(TestResult5) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool result = false;
  bool retval = false;
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", "EXISTS k", 1000);
    retval = ret->get_return(result);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
  ASSERT_TRUE(retval);
}

CASE(TestResult6) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool result = false;
  bool retval = false;
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", "EXISTS xdsss", 1000);
    retval = ret->get_return(result);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(!result);
  ASSERT_TRUE(retval);
}

CASE(TestResult7) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  std::vector<std::string> v;
  bool retval = false;
  coro_start([&](void *) {
    auto ret1 = redis.do_command_co("test", "SADD sk 1 2 3", 1000);
    auto ret2 = redis.do_command_co("test", "SMEMBERS sk", 1000);
    retval = ret2->get_return(v);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  if (!v.empty()) {
    ASSERT_TRUE(v[0] == "1");
  } else {
    ASSERT_TRUE(false);
  }
  ASSERT_TRUE(retval);
}

CASE(TestResult8) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  std::unordered_set<std::string> v;
  bool retval = false;
  coro_start([&](void *) {
    auto ret1 = redis.do_command_co("test", "SADD sk 1 2 3", 1000);
    auto ret2 = redis.do_command_co("test", "SMEMBERS sk", 1000);
    retval = ret2->get_return(v);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  if (v.empty()) {
    ASSERT_TRUE(false);
  }
  ASSERT_TRUE(retval);
}

CASE(TestResult9) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  std::unordered_map<std::string, std::string> m;
  bool retval = false;
  coro_start([&](void *) {
    auto ret1 = redis.do_command_co("test", "HSET hk k v", 1000);
    auto ret2 = redis.do_command_co("test", "HGETALL hk", 1000);
    retval = ret2->get_return(m);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  if (m.empty()) {
    ASSERT_TRUE(false);
  }
  ASSERT_TRUE(retval);
}

CASE(TestResult10) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  std::vector<std::string> l;
  bool retval = false;
  coro_start([&](void *) {
    auto ret1 = redis.do_command_co("test", "LPUSH lk 1 2 3", 1000);
    auto ret2 = redis.do_command_co("test", "LRANGE lk 0 -1", 1000);
    retval = ret2->get_return(l);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  if (l.empty()) {
    ASSERT_TRUE(false);
  }
  ASSERT_TRUE(retval);
}

CASE(TestResult11) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  std::list<std::string> l;
  bool retval = false;
  coro_start([&](void *) {
    auto ret1 = redis.do_command_co("test", "LPUSH lk 1 2 3", 1000);
    auto ret2 = redis.do_command_co("test", "LRANGE lk 0 -1", 1000);
    retval = ret2->get_return(l);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  if (l.empty()) {
    ASSERT_TRUE(false);
  }
  ASSERT_TRUE(retval);
}

FIXTURE_END(test_redis)
